package com.cloudcode.repository;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.cloudcode.document.DocumentContent;
import com.cloudcode.dto.resp.DocumentContentResp;
import com.cloudcode.enums.DocumentTypeEnum;
import io.micrometer.common.util.StringUtils;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.client.elc.NativeQueryBuilder;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.HighlightQuery;
import org.springframework.data.elasticsearch.core.query.highlight.Highlight;
import org.springframework.data.elasticsearch.core.query.highlight.HighlightField;
import org.springframework.data.elasticsearch.core.query.highlight.HighlightFieldParameters;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;


/**
 * @Author yunst
 * @data 2023/10/24 17:20
 */
@Component
@Slf4j
public class DocumentRepositoryPlus {
    @Resource
    private ElasticsearchOperations elasticsearchOperations;

    @Resource
    private ElasticsearchTemplate elasticsearchTemplate;

    /**
     * 全局搜索
     */
    public Page<DocumentContentResp> querySearchAfterTitleAndContent(String keyword, String lastId, Integer size) {
        //构建查询条件
        NativeQueryBuilder nativeQueryBuilder = buildNativeQuery(keyword, lastId, size);
        SearchHits<DocumentContent> searchHits = elasticsearchOperations.search(nativeQueryBuilder.build(), DocumentContent.class);
        log.info(JSON.toJSONString(searchHits));
        Page<DocumentContentResp> documentContentRespPage = new Page();
        if (searchHits.getTotalHits() <= 0) {
            return documentContentRespPage;
        }
        buildSearchData(searchHits, documentContentRespPage);
        documentContentRespPage.setSize(size);
        documentContentRespPage.setTotal(searchHits.getTotalHits());
        return documentContentRespPage;
    }

    private void buildSearchData(SearchHits<DocumentContent> search, Page<DocumentContentResp> documentContentRespPage) {
        List<DocumentContentResp> documentContentRespList = search.getSearchHits().stream().map(item -> {
            DocumentContentResp documentContentResp = new DocumentContentResp();
            DocumentContent content = item.getContent();
            List<String> titleValue = item.getHighlightField("title");
            List<String> contentValue = item.getHighlightField("content");
            if (CollectionUtil.isNotEmpty(titleValue)) {
                String titleStr = titleValue.stream().collect(Collectors.joining(" "));
                documentContentResp.setTitle(titleStr);
            } else {
                documentContentResp.setTitle(content.getTitle());
            }
            if (CollectionUtil.isNotEmpty(contentValue)) {
                String contentStr = contentValue.stream().collect(Collectors.joining(" "));
                documentContentResp.setContent(contentStr);
            } else {
                documentContentResp.setContent(content.getContent());
            }
            if (StringUtils.isNotBlank(content.getImgUrl())) {
                documentContentResp.setImg(Arrays.stream(content.getImgUrl().split(";")).collect(Collectors.toList()));
            }
            if (content.getType().equals(DocumentTypeEnum.BRIEF_INTRODUCTION.getCode())) {
                documentContentResp.setCareer(content.getCareer());
            }
            documentContentResp.setPath(content.getPath());
            documentContentResp.setType(DocumentTypeEnum.getCodeValue(content.getType()));
            documentContentResp.setId(String.valueOf(content.getId()));
            return documentContentResp;
        }).collect(Collectors.toList());
        documentContentRespPage.setRecords(documentContentRespList);
    }

    private static NativeQueryBuilder buildNativeQuery(String keyword, String lastId, Integer size) {
        //查询关键字高亮显示
        List<HighlightField> highlightFieldList = new ArrayList<>();
        HighlightField highlightField = new HighlightField("title", HighlightFieldParameters.builder().withPreTags("<span style=\"color:red \">").withPostTags("</span>").build());
        highlightFieldList.add(highlightField);
        highlightField = new HighlightField("content", HighlightFieldParameters.builder().withPreTags("<span style=\"color:red \">").withPostTags("</span \">").build());
        highlightFieldList.add(highlightField);
        Highlight highlight = new Highlight(highlightFieldList);
        HighlightQuery highlightQuery = new HighlightQuery(highlight, DocumentContent.class);
        //构建查询条件，根据文档内容或者文档标题匹配满足一个即可，然后安装id进行排序查询最新文档数据，这里使用SearchAfter查询解决深分页问题
        NativeQueryBuilder nativeQueryBuilder = NativeQuery.builder().withQuery(q -> q.bool(bool -> bool.should(item -> item.match(match -> match.field("content").query(keyword))).should(item -> item.match(match -> match.field("title").query(keyword))))).withHighlightQuery(highlightQuery).withPageable(PageRequest.of(0, size)).withSort(Sort.by("id").descending());
        if (StringUtils.isNotBlank(lastId)) {
            nativeQueryBuilder.withSearchAfter(CollUtil.newArrayList(lastId));
        }
        return nativeQueryBuilder;
    }

    public List<DocumentContentResp> querySearchTitle(String keyword, Integer size) {
        NativeQuery nativeQuery = NativeQuery.builder().withQuery(q -> q.match(match -> match.field("title").query(keyword))).withSort(Sort.by("id").descending()).build();
        SearchHits<DocumentContent> searchHits = elasticsearchOperations.search(nativeQuery, DocumentContent.class);
        return searchHits.getSearchHits().stream().map(item -> {
            DocumentContentResp documentContentResp = new DocumentContentResp();
            documentContentResp.setTitle(item.getContent().getTitle());
            return documentContentResp;
        }).collect(Collectors.toList());
    }
}
